﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using WorldBankBBS.Data;
using WorldBankBBS.Handlers;
using WorldBankBBS.Input;
using WorldBankBBS.Resources;
using WorldBankBBS.Translators;

namespace WorldBankBBS.Logic
{
    public class GuestLoginHandler
    {
        private readonly ITranslator _translator = null;
        private readonly Session _session = null;

        public GuestLoginHandler(Session session)
        {
            _session = session;

            switch (session.Encoding)
            {
                case "PETSCII":
                    _translator = new CbmTranslator() {CurrentSession = session};
                    break;

                case "ANSI":
                    _translator = new AnsiTranslator() {CurrentSession = session};
                    break;

                default:
                    _translator = new AsciiTranslator() {CurrentSession = session};
                    break;
            }
        }
        public event TextInputHandler TextInput;

        public static void OnGuestLogin(object sender, Session session)
        {
            var handler = new GuestLoginHandler(session);
            handler.GuestLogin(session);
        }

        private void GuestLogin(Session session)
        {
            var inputHandler = new InputHandler();

            TextInput += inputHandler.OnTextInput;

            var buffer = new byte[1024];
            var user = "";
            var realName = "";
            var alias = "";
            var email = "";
            var website = "";
            var password = "";
            var confirm = "";

            var l = 0;
            var existing = true;

            var invalidPassword = true;
            var count = 0;

            if (_session.Encoding != "ASCII")
            {
                l = _translator.StringToBytes(buffer, StringTable.APP_FORM);
                _session.Connection.SendData(buffer, 0, l);

                l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_USER);
                _session.Connection.SendData(buffer, 0, l);

                while (existing)
                {
                    if (TextInput != null)
                    {
                        user = TextInput(_session, _translator, _session.Connection, 20, false);
                        if (user == string.Empty)
                        {
                            l = _translator.StringToBytes(buffer, "{CLEAR}");
                            _session.Connection.SendData(buffer, 0, l);
                            TextInput -= inputHandler.OnTextInput;

                            session.GuestLoginCompleted = false;
                            return;
                        }
                        else
                        {
                            existing = Data.User.UserExists(user);
                            //existing = true;
                            if (existing)
                            {
                                l = _translator.StringToBytes(buffer, StringTable.APP_USER_EXISTS);
                                _session.Connection.SendData(buffer, 0, l);
                            }
                        }
                    }
                }

                l = _translator.StringToBytes(buffer, StringTable.APP_CLEAR_STATUS);
                _session.Connection.SendData(buffer, 0, l);

                l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_USER);
                _session.Connection.SendData(buffer, 0, l);

                l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_REAL);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    realName = TextInput(_session, _translator, _session.Connection, 20, false);
                }

                l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_ALIAS);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    alias = TextInput(_session, _translator, _session.Connection, 20, false);
                }

                l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_EMAIL);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    email = TextInput(_session, _translator, _session.Connection, 37, false);
                }

                l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_WEB);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    website = TextInput(_session, _translator, _session.Connection, 37, false);
                }

                while (invalidPassword && count < 5)
                {
                    ++count;
                    l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_PASSWORD);
                    _session.Connection.SendData(buffer, 0, l);

                    l = _translator.StringToBytes(buffer, StringTable.APP_PASSWORD_CLEAR_LINE);
                    _session.Connection.SendData(buffer, 0, l);

                    if (TextInput != null)
                    {
                        password = TextInput(_session, _translator, _session.Connection, 20, true);
                    }

                    if (string.IsNullOrWhiteSpace(password))
                    {
                        l = _translator.StringToBytes(buffer, StringTable.APP_PASSWORD_REQUIRED);
                        _session.Connection.SendData(buffer, 0, l);
                        continue;
                    }

                    if (password.Length < 5)
                    {
                        l = _translator.StringToBytes(buffer, StringTable.APP_PASSWORD_TOO_SHORT);
                        _session.Connection.SendData(buffer, 0, l);
                        continue;
                    }

                    l = _translator.StringToBytes(buffer, StringTable.APP_CLEAR_STATUS);
                    _session.Connection.SendData(buffer, 0, l);

                    l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_PASSWORD);
                    _session.Connection.SendData(buffer, 0, l);

                    l = _translator.StringToBytes(buffer, StringTable.APP_NEXT_LINE_CONFIRM);
                    _session.Connection.SendData(buffer, 0, l);

                    l = _translator.StringToBytes(buffer, StringTable.APP_PASSWORD_CLEAR_LINE);
                    _session.Connection.SendData(buffer, 0, l);

                    if (TextInput != null)
                    {
                        confirm = TextInput(_session, _translator, _session.Connection, 20, true);
                    }

                    if (password == confirm)
                    {
                        invalidPassword = false;
                    }
                    else
                    {
                        l = _translator.StringToBytes(buffer, StringTable.APP_PASSWORD_DONT_MATCH);
                        _session.Connection.SendData(buffer, 0, l);
                    }
                }

                if (invalidPassword)
                {
                    l = _translator.StringToBytes(buffer, StringTable.APP_ABORTING);
                    _session.Connection.SendData(buffer, 0, l);
                }
                else
                {
                    var u = new Data.User
                    {
                        UserUID = Guid.NewGuid(),
                        UserName = user,
                        RealName = realName,
                        Alias = alias,
                        EMailAddress = email,
                        Website = website,
                        Password = MD5.Create().ComputeHash(ASCIIEncoding.ASCII.GetBytes(password)),
                    };

                    using (var helper = new ModelHelper())
                    {
                        helper.BeginNewContext();

                        helper.Context.Users.Add(u);

                        try
                        {
                            helper.Context.SaveChanges();

                            Log.WriteLogEntry("AUDIT", string.Format("Created User: {0}", user),
                                DateTime.UtcNow);

                            l = _translator.StringToBytes(buffer, StringTable.APP_USER_CREATED);
                            _session.Connection.SendData(buffer, 0, l);
                        }
                        catch (Exception e)
                        {
                            Log.WriteLogEntry("ERROR", e.ToString(), DateTime.UtcNow);

                            l = _translator.StringToBytes(buffer, StringTable.APP_USER_ERROR);
                            _session.Connection.SendData(buffer, 0, l);
                        }
                    }
                }
            }
            else
            {
                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_LINE);
                _session.Connection.SendData(buffer, 0, l);

                while (existing)
                {
                    l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_USERNAME);
                    _session.Connection.SendData(buffer, 0, l);

                    if (TextInput != null)
                    {
                        user = TextInput(_session, _translator, _session.Connection, 20, false);
                        if (user == string.Empty)
                        {
                            l = _translator.StringToBytes(buffer, "{CLEAR}");
                            _session.Connection.SendData(buffer, 0, l);
                            TextInput -= inputHandler.OnTextInput;

                            l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_ABORTED);
                            _session.Connection.SendData(buffer, 0, l);

                            _session.GuestLoginCompleted = false;
                            return;
                        }
                        else
                        {
                            existing = Data.User.UserExists(user);
                            //existing = true;
                            if (existing)
                            {
                                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_EXISTS);
                                _session.Connection.SendData(buffer, 0, l);
                            }
                        }
                    }
                }

                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_LINE);
                _session.Connection.SendData(buffer, 0, l);

                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_REALNAME);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    realName = TextInput(_session, _translator, _session.Connection, 20, false);
                }


                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_LINE);
                _session.Connection.SendData(buffer, 0, l);

                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_ALIAS);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    alias = TextInput(_session, _translator, _session.Connection, 20, false);
                }

                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_LINE);
                _session.Connection.SendData(buffer, 0, l);

                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_EMAIL);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    email = TextInput(_session, _translator, _session.Connection, 79, false);
                }
                
                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_LINE);
                _session.Connection.SendData(buffer, 0, l);

                l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_WEBSITE);
                _session.Connection.SendData(buffer, 0, l);

                if (TextInput != null)
                {
                    website = TextInput(_session, _translator, _session.Connection, 79, false);
                }

                while (invalidPassword && count < 5)
                {
                    ++count;

                    l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_LINE);
                    _session.Connection.SendData(buffer, 0, l);

                    l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_PASSWORD);
                    _session.Connection.SendData(buffer, 0, l);

                    if (TextInput != null)
                    {
                        password = TextInput(_session, _translator, _session.Connection, 20, true);
                    }

                    if (string.IsNullOrWhiteSpace(password))
                    {
                        l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_REQUIRED);
                        _session.Connection.SendData(buffer, 0, l);
                        continue;
                    }

                    if (password.Length < 5)
                    {
                        l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_TOO_SHORT);
                        _session.Connection.SendData(buffer, 0, l);
                        continue;
                    }

                    l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_LINE);
                    _session.Connection.SendData(buffer, 0, l);

                    l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_CONFIRM);
                    _session.Connection.SendData(buffer, 0, l);

                    if (TextInput != null)
                    {
                        confirm = TextInput(_session, _translator, _session.Connection, 20, true);
                    }

                    if (password == confirm)
                    {
                        invalidPassword = false;
                    }
                    else
                    {
                        l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_DONT_MATCH);
                        _session.Connection.SendData(buffer, 0, l);
                    }
                }

                if (invalidPassword)
                {
                    l = _translator.StringToBytes(buffer, StringTable.APP_ASCII_ABORTED);
                    _session.Connection.SendData(buffer, 0, l);
                }
                else
                {
                    var u = new Data.User
                    {
                        UserUID = Guid.NewGuid(),
                        UserName = user,
                        RealName = realName,
                        Alias = alias,
                        EMailAddress = email,
                        Website = website,
                        Password = MD5.Create().ComputeHash(ASCIIEncoding.ASCII.GetBytes(password)),
                    };

                    using (var helper = new ModelHelper())
                    {
                        helper.BeginNewContext();

                        helper.Context.Users.Add(u);

                        try
                        {
                            helper.Context.SaveChanges();

                            Log.WriteLogEntry("AUDIT", string.Format("Created User: {0}", user),
                                DateTime.UtcNow);

                            l = _translator.StringToBytes(buffer, StringTable.APP_USER_CREATED);
                            _session.Connection.SendData(buffer, 0, l);
                        }
                        catch (Exception e)
                        {
                            Log.WriteLogEntry("ERROR", e.ToString(), DateTime.UtcNow);

                            l = _translator.StringToBytes(buffer, StringTable.APP_USER_ERROR);
                            _session.Connection.SendData(buffer, 0, l);
                        }
                    }
                }
            }
            TextInput -= inputHandler.OnTextInput;
            _session.GuestLoginCompleted = false;
        }
    }
}
